package logservice

import (
	"fmt"
	"os"
	"path"
	"time"
)

//向文件中写日志

type FileLogger struct {
	Level       LogLevel
	filePath    string //日志文件保存的路径
	fileName    string //日志文件名
	fileObj     *os.File
	errFileObj  *os.File
	maxFileSize uint64
}

func NewFileLogger(levelstr, fp, fn string, maxSize uint64) *FileLogger {
	logLevel, err := parseLevel(levelstr)
	if err != nil {
		panic(err)
	}
	fl := &FileLogger{
		Level:       logLevel,
		filePath:    fp,
		fileName:    fn,
		maxFileSize: maxSize,
	}
	err = fl.initFile() //按照文件路径和文件名将文件打开
	if err != nil {
		panic(err)
	}
	return fl
}

func (fl *FileLogger) initFile() error {
	fullPn := path.Join(fl.filePath, fl.fileName)
	fileObj, err := os.OpenFile(fullPn, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Println("open log file failed,err", err)
		return err
	}
	errFileObj, err := os.OpenFile(fullPn+".err", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Println("open err log file failed,err", err)
		return err
	}
	fl.errFileObj = errFileObj
	fl.fileObj = fileObj
	return nil
}

func (fl *FileLogger) enable(logLevel LogLevel) bool {
	return logLevel >= fl.Level
}

func (fl *FileLogger) printLog(format string, lv LogLevel, a ...interface{}) {
	msg := fmt.Sprintf(format, a...)
	now := time.Now()
	funcName, fileName, lineNo := getInfo(3)
	if fl.checkSize(fl.fileObj) {
		newFile, err := fl.splitFile(fl.fileObj)
		if err != nil {
			fmt.Println("分割文件错误:", err)
			return
		}
		fl.fileObj = newFile
	}
	fmt.Fprintf(fl.fileObj, "[%s][%s](%s:%s:%d)%s\n", now.Format("2006-01-02 15:04:05"), logLevelToStr(lv), funcName, fileName, lineNo, msg)
	if lv >= ERROR {
		if fl.checkSize(fl.errFileObj) {
			newFile, err := fl.splitFile(fl.errFileObj)
			if err != nil {
				fmt.Println("分割文件错误:", err)
				return
			}
			fl.errFileObj = newFile
		}
		//如果记录的日志级别大于ERROR，需要在err文件中再记录一次
		fmt.Fprintf(fl.errFileObj, "[%s][%s](%s:%s:%d)%s\n", now.Format("2006-01-02 15:04:05"), logLevelToStr(lv), funcName, fileName, lineNo, msg)
	}
}

func (fl *FileLogger) splitFile(f *os.File) (*os.File, error) {
	//如果日志文件大于允许大小则切割文件
	fs, _ := f.Stat()
	nowStr := time.Now().Format("20060102150405000")
	logName := path.Join(fl.filePath, fs.Name()) //获取当前文件的完整路径
	newFileName := fmt.Sprintf("%s.bak%s", fs.Name(), nowStr)
	//1.关闭当前日志文件
	f.Close()
	//2.重命名

	os.Rename(logName, newFileName)
	//3.打开一个新的日志文件
	fileObj, err := os.OpenFile(logName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		fmt.Println("open file err:", err)
		return nil, err
	}
	//4.将新的日志文件对象赋值给f.fileObj
	return fileObj, nil
}

func (fl *FileLogger) Debug(format string, a ...interface{}) {
	fl.printLog(format, DEBUG, a...)
}

func (fl *FileLogger) Info(format string, a ...interface{}) {
	fl.printLog(format, INFO, a...)
}

func (fl *FileLogger) Warning(format string, a ...interface{}) {
	fl.printLog(format, WARNING, a...)

}

func (fl *FileLogger) Trace(format string, a ...interface{}) {
	fl.printLog(format, TRACE, a...)
}

func (fl *FileLogger) Error(format string, a ...interface{}) {
	fl.printLog(format, ERROR, a...)
}

func (fl *FileLogger) Fatal(format string, a ...interface{}) {
	fl.printLog(format, FATAL, a...)
}

func (f *FileLogger) Close() {
	f.errFileObj.Close()
	f.fileObj.Close()
}

func (f *FileLogger) checkSize(file *os.File) bool {
	fs, err := file.Stat()
	if err != nil {
		fmt.Println("get file stat error:", err)
		return false
	}
	//如果当前文件大小大于等于日志文件允许的最大值，返回true
	return fs.Size() >= int64(f.maxFileSize)
}
